package nbp.currency.logic;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import nbp.currency.gui.TableColumnEnum;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

public class NBPService {

	private static NBPService service;
	private static String URL_NBP = "http://www.nbp.pl/kursy/xml/";
	private static String URL_DIR_FILE = URL_NBP + "dir.txt";
	private static String RESOURCE_PATH = "currencyFiles"+File.separator;
	private static String EXTENSION = ".xml";

	private Map<TypeOfExchange, Map<String, String>> filesName;
	private static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyMMdd");

	private NBPService() {
	};

	public static synchronized NBPService getInstance() {
		if (service == null) {
			service = new NBPService();
		}
		return service;
	}

	public List<CurrencyWrapper> getCurrency(Date to, Date from, TypeOfExchange tableType) {

		if (!isDirectoryInResource("")) {
			makeDirectories();
		}

		Calendar fromCalendar = GregorianCalendar.getInstance();
		fromCalendar.setTime(from);

		List<CurrencyWrapper> currencyWrappers = new ArrayList<CurrencyWrapper>();

		while (fromCalendar.getTime().compareTo(to) <= 0) {

			String date = DATE_FORMAT.format(fromCalendar.getTime());
			if (!isFileInResource(tableType.getTableType() + File.separator + date + EXTENSION)) {
				getXMLFileFromNBP(date, tableType);
				System.out.println("nie ma");
			}

			try {

				if (isFileInResource(tableType.getTableType() + File.separator + date + EXTENSION)) {
					currencyWrappers.addAll(parseXML(RESOURCE_PATH + tableType.getTableType() + File.separator + date + EXTENSION));
				}
			} catch (JDOMException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

			fromCalendar.add(Calendar.DAY_OF_YEAR, 1);
		}

		return currencyWrappers;

	}

	private void getXMLFileFromNBP(String date, TypeOfExchange tableType) {
		String string = getFilesNameMap().get(tableType).get(date);
		System.out.println(string);
		if (string != null) {
			copyFileFromNBP(string, tableType, date);
		}
	}

	public static void main(String[] args) {
		NBPService.getInstance().getCurrency(new Date(), new Date(), TypeOfExchange.PURCHASE_SALE);
	}

	private Collection<? extends CurrencyWrapper> parseXML(String fileName) throws JDOMException, IOException {
		List<CurrencyWrapper> result = new ArrayList<CurrencyWrapper>();
		SAXBuilder jdomBuilder = new SAXBuilder();
		Document jdomDocument = jdomBuilder.build(fileName);
		Element rss = jdomDocument.getRootElement();
		String dateText = rss.getChildText("data_publikacji");
		Date date = null;
		try {
			date = new SimpleDateFormat("yyyy-MM-dd").parse(dateText);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		List<Element> channel = rss.getChildren("pozycja");

		for (Element element : channel) {
			CurrencyWrapper createCurrencyWrapper = createCurrencyWrapper(element, date);
			result.add(createCurrencyWrapper);
		}

		return result;
	}

	private CurrencyWrapper createCurrencyWrapper(Element currency, Date date) {
		if (currency != null) {
			CurrencyWrapper currencyWrapper = new CurrencyWrapper();
			currencyWrapper.setDate(date);
			currencyWrapper.setConverter(currency.getChildText(TableColumnEnum.CONVERTER.getXmlName()));
			currencyWrapper.setCurrencyCode(currency.getChildText(TableColumnEnum.CODE.getXmlName()));
			String averageText = currency.getChildText(TableColumnEnum.AVERAGE_EXCHANGE.getXmlName());
			BigDecimal average = getBigDecimal(averageText);
			if (average != null) {
				currencyWrapper.setAverageExchange(average);
			}

			String buyText = currency.getChildText(TableColumnEnum.BUY_EXCHANGE.getXmlName());
			BigDecimal buy = getBigDecimal(buyText);
			if (buyText != null) {
				currencyWrapper.setBuyExchange(buy);
			}

			String sellText = currency.getChildText(TableColumnEnum.SELL_EXCHANGE.getXmlName());
			BigDecimal sell = getBigDecimal(sellText);
			if (sell != null) {
				currencyWrapper.setSellExchange(sell);
			}
			return currencyWrapper;
		}
		return null;
	}

	private void copyFileFromNBP(String fileName, TypeOfExchange tableType, String copyFileName) {
		InputStream inStream = null;
		OutputStream outStream = null;
		try {
			URL url = new URL(URL_NBP + fileName);

			inStream = url.openStream();
			outStream = new FileOutputStream(RESOURCE_PATH + tableType.getTableType() + File.separator + copyFileName + EXTENSION);

			byte[] buffer = new byte[1024];
			int length;
			while ((length = inStream.read(buffer)) > 0) {
				outStream.write(buffer, 0, length);
			}

			inStream.close();
			outStream.flush();
			outStream.close();

		} catch (IOException e) {
			e.printStackTrace();
		}
		System.err.println("Skopiowano: " + fileName);
	}

	private boolean isFileInResource(String fileName) {
		File file = new File(RESOURCE_PATH + fileName);
		if (file.exists() && !file.isDirectory()) {
			return true;
		}
		return false;
	}

	private boolean isDirectoryInResource(String directoryName) {
		File file = new File(RESOURCE_PATH + directoryName);
		if (file.exists() && file.isDirectory()) {
			return true;
		}
		return false;
	}

	private void makeDirectories() {

		File average = new File(RESOURCE_PATH + TypeOfExchange.AVERAGE_FOREIGN.getTableType());
		File averageUnconvertible = new File(RESOURCE_PATH + TypeOfExchange.AVERAGE_INCONVERTIBLE.getTableType());
		File buySell = new File(RESOURCE_PATH + TypeOfExchange.PURCHASE_SALE.getTableType());
		average.mkdirs();
		averageUnconvertible.mkdirs();
		buySell.mkdirs();

	}

	private Map<TypeOfExchange, Map<String, String>> getFilesNameMap() {

		if (filesName == null) {
			URL url;
			InputStream inputStream;
			filesName = new HashMap<TypeOfExchange, Map<String, String>>();
			for (TypeOfExchange type : TypeOfExchange.values()) {
				filesName.put(type, new HashMap<String, String>());
			}

			try {
				url = new URL(URL_DIR_FILE);
				inputStream = url.openStream();
				Scanner scanner = new Scanner(inputStream, "UTF-8");
				while (scanner.hasNextLine()) {
					String fileName = scanner.nextLine();

					if (fileName.startsWith("\uFEFF")) {
						fileName = fileName.substring(1);
					}

					String type = String.valueOf(fileName.charAt(0));
					String date = getDate(fileName);
					TypeOfExchange t = TypeOfExchange.getByType(type);
					if (t != null) {
						filesName.get(TypeOfExchange.getByType(type)).put(date, fileName + EXTENSION);
					}
				}
				scanner.close();
			} catch (Exception e) {
				filesName = new HashMap<TypeOfExchange, Map<String, String>>();
			}
		}

		return filesName;
	}

	private BigDecimal getBigDecimal(String text) {
		if (text != null) {
			return new BigDecimal(text.replace(",", "."));
		}
		return null;
	}

	private String getDate(String text) throws Exception {
		String substring = text.substring(5);
		return substring;
	}
}
